`timescale 1 ns / 1 ns
//////////////////////////////////////////////////////////////////////////////////
// Company: Rehkopf
// Engineer: Rehkopf
//
// Create Date:    01:13:46 05/09/2009
// Design Name:
// Module Name:    address
// Project Name:
// Target Devices:
// Tool versions:
// Description: Address logic w/ SaveRAM masking
//
// Dependencies:
//
// Revision:
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module address(
  input CLK,
  input [15:0] featurebits, // peripheral enable/disable
  input [2:0] MAPPER,       // MCU detected mapper
  input [23:0] SNES_ADDR,   // requested address from SNES
  input [7:0] SNES_PA,      // peripheral address from SNES
  input SNES_ROMSEL,        // ROMSEL from SNES
  output [23:0] ROM_ADDR,   // Address to request from SRAM0
  output ROM_HIT,           // enable SRAM0
  output IS_SAVERAM,        // address/CS mapped as SRAM?
  output IS_ROM,            // address mapped as ROM?
  output IS_WRITABLE,       // address somehow mapped as writable area?
  input [23:0] SAVERAM_MASK,
  input [23:0] ROM_MASK,
  output msu_enable,
  output srtc_enable,
  output use_bsx,
  output bsx_tristate,
  input [14:0] bsx_regs,
  output dspx_enable,
  output dspx_dp_enable,
  output dspx_a0,
  output r213f_enable,
  output r2100_hit,
  output snescmd_enable,
  output nmicmd_enable,
  output return_vector_enable,
  output branch1_enable,
  output branch2_enable,
  output branch3_enable
);

/* feature bits. see src/fpga_spi.c for mapping */
parameter [2:0]
  FEAT_DSPX = 0,
  FEAT_ST0010 = 1,
  FEAT_SRTC = 2,
  FEAT_MSU1 = 3,
  FEAT_213F = 4,
  FEAT_2100 = 6
;

wire [23:0] SRAM_SNES_ADDR;

/* currently supported mappers:
   Index     Mapper
      000      HiROM
      001      LoROM
      010      ExHiROM (48-64Mbit)
      011      BS-X
      100      ExLoROM (StarOCean and SFA2)
      110      brainfuck interleaved 96MBit Star Ocean =)
      111      menu (ROM in upper SRAM)
*/

// active high to select ROM in banks 00-3f,80-bf:8000-ffff and 40-7d,c0-ff:0000-ffff
// (decoded by SNES)
assign IS_ROM = ~SNES_ROMSEL;

// select backup RAM when
              // ST0010 chip is present, SRAM is mapped to
assign IS_SAVERAM = SAVERAM_MASK[0]&(featurebits[FEAT_ST0010]?((SNES_ADDR[22:19] == 4'b1101) & &(~SNES_ADDR[15:12]) & SNES_ADDR[11])
              // for HiROM, ExtHIROM or interleaved StarOcean -> $3X:[$6000-$7FFF] or $BX:[$6000-$7FFF]
              :((MAPPER == 3'b000 || MAPPER == 3'b010 || MAPPER == 3'b110) ? (!SNES_ADDR[22] & SNES_ADDR[21] & &SNES_ADDR[14:13] & !SNES_ADDR[15])
              // for ExtLoROM -> $7X:[$6000-$7FFF]
              :(MAPPER == 3'b100) ? ((SNES_ADDR[23:19] == 5'b01110) && (SNES_ADDR[15:13] == 3'b011))
              // LoROM:   SRAM @ Bank 0x70-0x7d, 0xf0-0xff
              // Offset 0000-7fff for ROM >= 32 MBit, otherwise 0000-ffff
              :(MAPPER == 3'b001)? (&SNES_ADDR[22:20] & (~SNES_ROMSEL) & (~SNES_ADDR[15] | ~ROM_MASK[21]))
              // BS-X: SRAM @ Bank 0x10-0x17 Offset 5000-5fff
              :(MAPPER == 3'b011) ? ((SNES_ADDR[23:19] == 5'b00010) & (SNES_ADDR[15:12] == 4'b0101) )
              // Menu mapper: 8Mbit "SRAM" @ Bank 0xf0-0xff (entire banks!)
              :(MAPPER == 3'b111) ? (&SNES_ADDR[23:20])
              : 1'b0));

// '1' to signal access to cartrigde writable range (Backup RAM or BS-X RAM)
assign IS_WRITABLE = IS_SAVERAM;

/* BSX regs:
 Index  Function
    1   0=map flash to ROM area; 1=map PRAM to ROM area
    2   1=HiROM; 0=LoROM
    3   1=Mirror PRAM @60-6f:0000-ffff
    5   1=DO NOT mirror PRAM @40-4f:0000-ffff
    6   1=DO NOT mirror PRAM @50-5f:0000-ffff
    7   1=map BSX cartridge ROM @00-1f:8000-ffff
    8   1=map BSX cartridge ROM @80-9f:8000-ffff
*/
                // HiROM
assign SRAM_SNES_ADDR = ((MAPPER == 3'b000) ? (IS_SAVERAM	? 24'hE00000 + ({SNES_ADDR[20:16], SNES_ADDR[12:0]} & SAVERAM_MASK)
                                        : ({1'b0, SNES_ADDR[22:0]} & ROM_MASK))
                // LoROM
                :(MAPPER == 3'b001) ? (IS_SAVERAM 	? 24'hE00000 + ({SNES_ADDR[20:16], SNES_ADDR[14:0]} & SAVERAM_MASK)
                                        : ({1'b0, ~SNES_ADDR[23], SNES_ADDR[22:16], SNES_ADDR[14:0]} & ROM_MASK))
                // ExtHiROM
                :(MAPPER == 3'b010) ? (IS_SAVERAM 	? 24'hE00000 + ({7'b0000000, SNES_ADDR[19:16], SNES_ADDR[12:0]} & SAVERAM_MASK)
                                        : ({1'b0, !SNES_ADDR[23], SNES_ADDR[21:0]} & ROM_MASK))
                // ExtLoROM
                :(MAPPER == 3'b100) ? (IS_SAVERAM 	? 24'hE00000 + ({7'b0000000, SNES_ADDR[19:16], SNES_ADDR[12:0]} & SAVERAM_MASK)
                                        : ({1'b0, !SNES_ADDR[23], SNES_ADDR[21:0]} & ROM_MASK))
                // interleaved StarOcean
                :(MAPPER == 3'b110) ? (IS_SAVERAM	? 24'hE00000 + ((SNES_ADDR[14:0] - 15'h6000) & SAVERAM_MASK)
                                        :(SNES_ADDR[15] ? ({1'b0, SNES_ADDR[23:16], SNES_ADDR[14:0]})
                                        :({2'b10, SNES_ADDR[23], SNES_ADDR[21:16], SNES_ADDR[14:0]}) ) )
                // menu
                :(MAPPER == 3'b111) ? (IS_SAVERAM	? SNES_ADDR
                                        : (({1'b0, SNES_ADDR[22:0]} & ROM_MASK) + 24'hC00000) )
                : 24'b0);

assign ROM_ADDR = SRAM_SNES_ADDR;

// '1' when accesing PSRAM for ROM, Backup RAM, BS-X RAM
assign ROM_HIT = IS_ROM | IS_WRITABLE;

// '1' when accessing to MSU register map $2000:$2007
assign msu_enable = featurebits[FEAT_MSU1] & (!SNES_ADDR[22] && ((SNES_ADDR[15:0] & 16'hfff8) == 16'h2000));

// MAGNO -> disabled for S-DD1 core
//assign use_bsx = (MAPPER == 3'b011);
assign use_bsx = 1'b0;

// MAGNO -> disabled for S-DD1 core
//assign srtc_enable = featurebits[FEAT_SRTC] & (!SNES_ADDR[22] && ((SNES_ADDR[15:0] & 16'hfffe) == 16'h2800));
assign srtc_enable = 1'b0;

assign r213f_enable = featurebits[FEAT_213F] & (SNES_PA == 8'h3f);
assign r2100_hit = (SNES_PA == 8'h00);

assign snescmd_enable = ({SNES_ADDR[22], SNES_ADDR[15:9]} == 8'b0_0010101);
assign nmicmd_enable = (SNES_ADDR == 24'h002BF2);
assign return_vector_enable = (SNES_ADDR == 24'h002A6C);
assign branch1_enable = (SNES_ADDR == 24'h002A1F);
assign branch2_enable = (SNES_ADDR == 24'h002A59);
assign branch3_enable = (SNES_ADDR == 24'h002A5E);
endmodule
